#include "Plane.h"
#include "Fysics/System/ResourceManager.h"
#include "Fysics/Renderer/Renderer.h"
#include "Fysics/Renderer/Text.h"
#include "Fysics/Renderer/Panel.h"

namespace Fysics
{
	Plane::Plane(const std::string& id, const std::string& name, int width, int height,
		const glm::vec3& position, const glm::vec3& rotation, const glm::vec3& scaling)
		: Object(id, name, position, rotation, scaling), m_Texture(nullptr), 
		m_Baked(false), m_ResolutionScaling(1.0f)
	{
		if (width < 0)
			m_Width = 100;
		else
			m_Width = width;
		if (height < 0)
			m_Height = 100;
		else
			m_Height = height;

		GenMesh();
		ShaderProgram* shaderProgram = ResourceManager::GetInstance()
			->GetShaderProgram("res/shader/Standard.vert", "res/shader/Panel.frag");
		m_Mesh->GetMaterial().SetShaderProgram(shaderProgram);

		m_Panel.SetWidth(1)
			.SetHeight(1)
			.SetBaseColor(glm::vec3(0.7f, 0.3f, 0.3f));

		ReBake();

		SetType(ObjectType::PLANE);
	}

	Plane::~Plane()
	{
		delete m_Mesh;
		delete m_Texture;
	}

	void Plane::GenMesh()
	{
		m_Mesh = new Mesh();

		Vertex vertices[] = {
			{{(-float(m_Width) / 200), (-float(m_Height) / 200), 0}, { 0, 0, 0 }, {0.f, 0.f} },
			{{(float(m_Width) / 200), (-float(m_Height) / 200), 0}, { 0, 0, 0 }, {1.f, 0.f} },
			{{(float(m_Width) / 200), (float(m_Height) / 200), 0}, { 0, 0, 0 }, {1.f, 1.f} },
			{{(-float(m_Width) / 200), (float(m_Height) / 200), 0}, { 0, 0, 0 }, {0.f, 1.f} }
		};

		unsigned int indices[] = {
			0, 1, 2,
			2, 3, 0
		};

		VertexArray* va = VertexArray::Create();

		VertexBuffer* vb = VertexBuffer::Create(vertices, 4, sizeof(Vertex));
		BufferLayout layout = {
			{ ShaderDataType::Float3, "position" },
			{ ShaderDataType::Float3, "normal" },
			{ ShaderDataType::Float2, "texture_coord" }
		};
		vb->SetLayout(layout);
		va->AddVertexBuffer(vb);

		IndexBuffer* ib = IndexBuffer::Create(indices, 6);
		va->SetIndexBuffer(ib);

		m_Mesh->SetVertexArray(va);
	}

	void Plane::OnEvent(Event& event)
	{
	}

	void Plane::Draw() const
	{
		Renderer::SubmitModelMatrix(GetModelMatrix());
		m_Mesh->Draw();
	}

	Plane& Plane::AddText(Ref<Text>& text)
	{
		unsigned int real_width = m_Width * m_ResolutionScaling;
		unsigned int real_height = m_Height * m_ResolutionScaling;
		m_Panel.AddText(text)
			.SetWidth(real_width)
			.SetHeight(real_height);

		m_Baked = false;
		return *this;
	}

	Plane& Plane::SetResolutionScaling(float scaling)
	{
		if (scaling <= 0)
			m_ResolutionScaling = 0.1f;
		else
			m_ResolutionScaling = scaling;
		m_Baked = false;
		return *this;
	}

	Plane& Plane::SetBgColor(const glm::vec3& background_color)
	{
		m_Panel.SetBaseColor(background_color);
		m_Baked = false;
		return *this;
	}

	void Plane::ReBake()
	{
		if (m_Baked)
		{
			return;
		}
		delete m_Texture;
		m_Texture = m_Panel.BakeTexture();
		m_Mesh->GetMaterial().AddTexture("u_Image", m_Texture);
		m_Baked = true;
	}
}